# -*- coding: utf-8 -*-

from task.models import AnsibleInventory
from rest_framework import serializers
from assets.models import *
from utils.crypt_pwd import CryptPwd
from fort.models import *
from projs.models import *
from dbmanager.models import *
from django_celery_beat.models import PeriodicTask
from wiki.models import Post
import datetime
from django.db.models import Q
import re


class AssetsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Assets
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(AssetsSerializer, self).__init__(*args, **kwargs)
        self.fields['asset_purchase_day'].error_messages['invalid'] = u'%s 格式不正确，请重新下拉选择'%self.fields['asset_purchase_day'].label
        self.fields['asset_expire_day'].error_messages['invalid'] = u'%s 格式不正确，请重新下拉选择' % self.fields['asset_expire_day'].label

    def validate(self, attrs):
        if(attrs['asset_purchase_day']>attrs['asset_expire_day']):
            raise serializers.ValidationError("到期/过保日期不能早于申请/购买日期")
        return attrs

class IPGroupSerializer(serializers.ModelSerializer):
    IP = serializers.IPAddressField()

    class Meta:
        model = IPGroup
        fields = '__all__'

class AssetsListSerializer(serializers.ModelSerializer):
    asset_management_ip  = IPGroupSerializer()
    serverassets = serializers.PrimaryKeyRelatedField(required=False, queryset=ServerAssets.objects.all())
    networkassets = serializers.PrimaryKeyRelatedField(required=False, queryset=NetworkAssets.objects.all())
    officeassets = serializers.PrimaryKeyRelatedField(required=False, queryset=OfficeAssets.objects.all())
    securityassets = serializers.PrimaryKeyRelatedField(required=False, queryset=SecurityAssets.objects.all())
    storageassets = serializers.PrimaryKeyRelatedField(required=False, queryset=StorageAssets.objects.all())
    softwareassets = serializers.PrimaryKeyRelatedField(required=False, queryset=SoftwareAssets.objects.all())
    asset_product = serializers.SerializerMethodField()
    hosted_on = serializers.SerializerMethodField()
    type_detail = serializers.SerializerMethodField()
    asset_status = serializers.SerializerMethodField()
    is_expired = serializers.SerializerMethodField()
    is_ssh = serializers.SerializerMethodField()
    has_username = serializers.SerializerMethodField()

    class Meta:
        model = Assets
        fields = '__all__'

    def get_asset_product(self, obj):
        product = obj.asset_product
        return product.product_name if product else ''

    def get_asset_status(self, obj):
        return [x for x in obj.asset_status_ if x[0] == obj.asset_status][0]

    def get_hosted_on(self, obj):
        if obj.asset_type == 'server':
            if obj.serverassets.hosted_on:
                hosted_on = obj.serverassets.hosted_on.assets.asset_management_ip
                if hosted_on != obj.asset_management_ip:
                    return hosted_on.IP
        else:
            return ''

    def get_type_detail(self, obj):
        if obj.asset_type == 'server':
            return [(x[0],obj.get_asset_type_display()+'-'+x[1]) for x in obj.serverassets.server_types if x[0] == obj.serverassets.server_type][0]
        elif obj.asset_type == 'network':
            return [(x[0],obj.get_asset_type_display()+'-'+x[1]) for x in obj.networkassets.network_types if x[0] == obj.networkassets.network_type][0]
        elif obj.asset_type == 'office':
            return [(x[0],obj.get_asset_type_display()+'-'+x[1]) for x in obj.officeassets.office_types if x[0] == obj.officeassets.office_type][0]
        elif obj.asset_type == 'security':
            return [(x[0],obj.get_asset_type_display()+'-'+x[1]) for x in obj.securityassets.security_types if x[0] == obj.securityassets.security_type][0]
        elif obj.asset_type == 'storage':
            return [(x[0],obj.get_asset_type_display()+'-'+x[1]) for x in obj.storageassets.storage_types if x[0] == obj.storageassets.storage_type][0]
        elif obj.asset_type == 'software':
            return [(x[0],obj.get_asset_type_display()+'-'+x[1]) for x in obj.softwareassets.software_types if x[0] == obj.softwareassets.software_type][0]

    def get_is_expired(self, obj):
        from api.filter import is_expired_types
        if datetime.date.today().__gt__(obj.asset_expire_day):
            return is_expired_types[1]#过期
        else:
            return is_expired_types[0]

    def get_is_ssh(self,obj):
        if obj.asset_type == 'server':
            if FortServer.objects.filter(server=obj.asset_management_ip, server_protocol='ssh').count() >0:
                return 1#有ssh连接
        return 0

    def get_has_username(self,obj):
        if obj.asset_type == 'server':
            if FortServerUser.objects.filter(~Q(fort_server__server_protocol='vnc'), Q(fort_server__server__asset_management_ip__id=obj.id)).count()>0:
                return 1
        return 0#需要新增用户


def assets_update(instance, validated_data):
    assets_data = validated_data.pop('assets', {})
    assets = instance.assets
    for attr, value in validated_data.items():
        setattr(instance, attr, value)
    instance.save()
    for attr, value in assets_data.items():
        setattr(assets, attr, value)
    assets.asset_update_time = datetime.datetime.now()
    assets.save()
    return instance

class ServerAssetsSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=False, required=False)

    class Meta:
        model = ServerAssets
        fields = '__all__'

    def create(self, data):
        if data.get('assets'):
            assets_data = data.pop('assets')
            assets = Assets.objects.create(**assets_data)
        else:
            assets = Assets()
        data['assets'] = assets
        server = ServerAssets.objects.create(**data)
        return server

    def update(self, instance, validated_data):
        return assets_update(instance, validated_data)


class NetworkAssetsSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=False, required=False)

    class Meta:
        model = NetworkAssets
        fields = '__all__'

    def create(self, data):
        if data.get('assets'):
            assets_data = data.pop('assets')
            assets = Assets.objects.create(**assets_data)
        else:
            assets = Assets()
        data['assets'] = assets
        network = NetworkAssets.objects.create(**data)
        return network

    def update(self, instance, validated_data):
        return assets_update(instance, validated_data)


class OfficeAssetsSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=False, required=False)

    class Meta:
        model = OfficeAssets
        fields = '__all__'

    def create(self, data):
        if data.get('assets'):
            assets_data = data.pop('assets')
            assets = Assets.objects.create(**assets_data)
        else:
            assets = Assets()
        data['assets'] = assets
        office = OfficeAssets.objects.create(**data)
        return office

    def update(self, instance, validated_data):
        return assets_update(instance, validated_data)


class SecurityAssetsSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=False, required=False)

    class Meta:
        model = SecurityAssets
        fields = '__all__'

    def create(self, data):
        if data.get('assets'):
            assets_data = data.pop('assets')
            assets = Assets.objects.create(**assets_data)
        else:
            assets = Assets()
        data['assets'] = assets
        security = SecurityAssets.objects.create(**data)
        return security

    def update(self, instance, validated_data):
        return assets_update(instance, validated_data)


class StorageAssetsSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=False, required=False)

    class Meta:
        model = StorageAssets
        fields = '__all__'

    def create(self, data):
        if data.get('assets'):
            assets_data = data.pop('assets')
            assets = Assets.objects.create(**assets_data)
        else:
            assets = Assets()
        data['assets'] = assets
        storage = StorageAssets.objects.create(**data)
        return storage

    def update(self, instance, validated_data):
        return assets_update(instance, validated_data)


class SoftwareAssetsSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=False, required=False)

    class Meta:
        model = SoftwareAssets
        fields = '__all__'

    def create(self, data):
        if data.get('assets'):
            assets_data = data.pop('assets')
            assets = Assets.objects.create(**assets_data)
        else:
            assets = Assets()
        data['assets'] = assets
        software = StorageAssets.objects.create(**data)
        return software

    def update(self, instance, validated_data):
        return assets_update(instance, validated_data)


class AssetProviderSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=True, read_only=True)

    class Meta:
        model = AssetProvider
        fields = (
            'id', 'asset_provider_name', 'asset_provider_contact', 'asset_provider_telephone', 'asset_provider_memo',
            'assets')


class CabinetSerializer(serializers.ModelSerializer):
    assets = AssetsSerializer(many=True, read_only=True)

    class Meta:
        model = Cabinet
        fields = ('id', 'idc', 'cabinet_name', 'cabinet_memo', 'assets')

    def __init__(self, *args, **kwargs):
        super(CabinetSerializer, self).__init__(*args, **kwargs)
        self.fields['idc'].error_messages['null'] = u'该字段不能为空。'


class IDCSerializer(serializers.ModelSerializer):
    cabinet = CabinetSerializer(many=True, read_only=True)
    assets = AssetsSerializer(many=True, read_only=True)

    class Meta:
        model = IDC
        fields = ('id', 'idc_name', 'idc_address', 'idc_contact', 'idc_telephone', 'idc_memo', 'cabinet', 'assets')


class InventorySerializer(serializers.ModelSerializer):
    class Meta:
        model = AnsibleInventory
        fields = '__all__'


class FortUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = FortServerUser
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(FortUserSerializer, self).__init__(*args, **kwargs)
        self.fields['fort_user_status'].error_messages['null'] = u'该字段不能为空。'
        self.fields['fort_code'].error_messages['null'] = u'该字段不能为空。'

    def find_protocol(self):
        if self.instance:
            return self.instance.fort_server.server_protocol
        else:
            return FortServer.objects.get(id=self.initial_data['fort_server']).server_protocol

    def validate_fort_username(self, value):
        if len(value) == 0 and self.find_protocol() != 'vnc':
            raise serializers.ValidationError("该字段不能为空。")
        return value

    def validate_fort_password(self, value):
        if len(value) == 0 and self.find_protocol() != 'vnc':
            raise serializers.ValidationError("密码不能为空。")
        if ' ' in value:
            raise serializers.ValidationError("密码不能包括空格。")
        if len(value) > 30:
            raise serializers.ValidationError("密码不能超过30位。")
        value = CryptPwd().encrypt_pwd(value)
        return value

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data.pop('fort_password')
        return data

class FortSerializer(serializers.ModelSerializer):
    class Meta:
        model = FortServer
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(FortSerializer, self).__init__(*args, **kwargs)
        self.fields['server_protocol'].error_messages['null'] = u'该字段不能为空。'
        self.fields['server_status'].error_messages['null'] = u'该字段不能为空。'
        self.fields['server'].error_messages['null'] = u'该字段不能为空。'

class FortListSerializer(serializers.ModelSerializer):
    server = IPGroupSerializer()
    fortserveruser_set = FortUserSerializer(many=True, required=False)
    asset = serializers.SerializerMethodField()

    class Meta:
        model = FortServer
        fields = '__all__'

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data.update(
            server_protocol=[instance.server_protocol,instance.get_server_protocol_display()],
            server_status=[instance.server_status, instance.get_server_status_display()],
                    )
        return data

    def get_asset(self, obj):
        return Assets.objects.filter(asset_management_ip=obj.server.id).values('id','asset_nu')


class FortListSerializer2(serializers.ModelSerializer):
    server = IPGroupSerializer()
    asset = serializers.SerializerMethodField()

    class Meta:
        model = FortServer
        fields = ['server', 'server_protocol', 'asset']

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data.update(server_protocol=[instance.server_protocol,instance.get_server_protocol_display()])
        return data

    def get_asset(self, obj):
        return Assets.objects.filter(asset_management_ip=obj.server.id).values('asset_nu')

class FortUserListSerializer(serializers.ModelSerializer):
    fort_server = FortListSerializer2()

    class Meta:
        model = FortServerUser
        fields = ["id", "fort_server", "fort_username", "fort_user_memo", 'fort_vnc_port']


class PeriodicTaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = PeriodicTask
        fields = '__all__'


class WebSiteSerializer(serializers.ModelSerializer):
    class Meta:
        model = WebSite
        fields = '__all__'


class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'


class NetworkCardAssetsSerializer(serializers.ModelSerializer):
    class Meta:
        model = NetworkCardAssets
        fields = '__all__'


class RamAssetsSerializer(serializers.ModelSerializer):
    class Meta:
        model = RamAssets
        fields = '__all__'


class IPSegmentSerializer(serializers.ModelSerializer):
    IP_category = serializers.SerializerMethodField()
    invalid_IP = serializers.SerializerMethodField()

    class Meta:
        model = IPSegment
        fields = '__all__'

    def get_IP_category(self, obj):
        all_groups = IPGroup.objects.filter(IP_segment=obj.id, IP_status=1).values('id', 'IP')
        valid_groups = Assets.objects.filter(
            asset_management_ip__IP_segment=obj.id, asset_management_ip__IP_status=1).values(
            'asset_management_ip__id', 'asset_management_ip__IP').distinct()
        all_count = all_groups.count()
        used_count = valid_groups.count()
        valid_groups_list = list(map(lambda x: x['asset_management_ip__id'], valid_groups))
        category = {}
        used = []
        idle = []
        for i in all_groups:
            if i['id'] not in valid_groups_list:
                idle.append({'id': i['id'], 'IP': i['IP']})
            else:
                used.append({'id': i['id'], 'IP': i['IP']})
        category['idle'] = {'count': all_count-used_count, 'items': idle}
        category['used'] = {'count': used_count, 'items': used}
        return category

    def get_invalid_IP(self, obj):
        invalid = IPGroup.objects.filter(IP_segment=obj.id, IP_status=0)
        return {'count': invalid.count(), 'items': invalid.values('id', 'IP')}


class DBAssetsConfigSerializer(serializers.ModelSerializer):
    db_IP = serializers.SerializerMethodField()

    class Meta:
        model = Assets
        fields = ['id', 'asset_nu', 'db_IP', 'asset_environment']

    def get_db_IP(self, obj):
        return obj.asset_management_ip.IP

class DBConfigSerializer(serializers.ModelSerializer):
    asset_nu = serializers.SerializerMethodField()
    db_IP = serializers.SerializerMethodField()

    class Meta:
        model = DBConfig
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(DBConfigSerializer, self).__init__(*args, **kwargs)
        self.fields['db_server'].error_messages['null'] = u'该字段不能为空。'
        self.fields['db_type'].error_messages['null'] = u'该字段不能为空。'

    def validate_db_password(self, value):
        if len(value) == 0:
            raise serializers.ValidationError("密码不能为空。")
        if ' ' in value:
            raise serializers.ValidationError("密码不能包括空格。")
        if len(value) > 30:
            raise serializers.ValidationError("密码不能超过30位。")
        value = CryptPwd().encrypt_pwd(value)
        return value

    def find_oracle_type(self):
        if self.instance:
            return self.initial_data.get('db_oracle_type', None) or self.instance.db_oracle_type
        else:
            return self.initial_data['db_oracle_type']

    def find_IP(self):
        try:
            if self.instance:
                return self.instance.db_server.asset_management_ip.IP
            else:
                return Assets.objects.get(id=self.initial_data['db_server']).asset_management_ip.IP
        except:
            return ''

    def validate_db_port(self, value):
        if self.find_oracle_type() != '1':
            if len(value) == 0:
                raise serializers.ValidationError("该字段不能为空。")
        return value

    def validate_db_name(self, value):
        if self.find_oracle_type() == '1':
            if len(value) == 0:
                raise serializers.ValidationError("该字段不能为空。")
            pattern = re.compile(r'^(((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3})[\D]{1}.+$')
            match_res = pattern.match(value)
            if not match_res:
                raise serializers.ValidationError("该字段格式不正确。")
            if match_res.groups(0)[0] != str(self.find_IP()):
                raise serializers.ValidationError("TNS务必与资产对应的IP地址关联。")
        return value

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data.pop('db_password')
        return data

    def get_asset_nu(self, obj):
        return obj.db_server.asset_nu

    def get_db_IP(self, obj):
        return obj.db_server.asset_management_ip.IP

class DBConfigListSerializer(serializers.ModelSerializer):
    db_server = DBAssetsConfigSerializer()

    class Meta:
        model = DBConfig
        exclude = ['db_password', 'db_port', 'db_memo' , 'db_code']

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data.update(db_type=[instance.db_type, instance.get_db_type_display()])
        return data

class ServerAssetsExportFortUserSerializer(serializers.ModelSerializer):
    fort_user_status = serializers.ChoiceField(choices=FortServerUser.fort_user_status_, source="get_fort_user_status_display")
    fort_password = serializers.SerializerMethodField()
    
    def get_fort_password(self,obj):
        return CryptPwd().decrypt_pwd(obj.fort_password)

    class Meta:
        model = FortServerUser
        fields = ["fort_username","fort_password","fort_user_status","fort_user_memo"]

class ServerAssetsExportFortListSerializer(serializers.ModelSerializer):
    fortserveruser_set = ServerAssetsExportFortUserSerializer(many=True, required=False)
    server_protocol = serializers.ChoiceField(choices=FortServer.server_protocols, source="get_server_protocol_display")

    class Meta:
        model = FortServer
        fields = ["fortserveruser_set","port","server_protocol"]

class ServerAssetsExportIPGroupSerializer(serializers.ModelSerializer):
    IP = serializers.IPAddressField()
    fortserver_set = ServerAssetsExportFortListSerializer(many=True, required=False)

    class Meta:
        model = IPGroup
        fields = ('fortserver_set', 'IP')

class ServerAssetsExportSerializer(serializers.ModelSerializer):
    asset_product = serializers.SerializerMethodField()
    hosted_on = serializers.SerializerMethodField()
    type_detail = serializers.SerializerMethodField()
    asset_status = serializers.ChoiceField(choices=Assets.asset_status_,source="get_asset_status_display")
    is_expired = serializers.SerializerMethodField()
    asset_environment = serializers.ChoiceField(choices=Assets.asset_environment_, source="get_asset_environment_display")
    asset_management_ip = ServerAssetsExportIPGroupSerializer()

    class Meta:
        model = Assets
        fields = ["id","asset_product","type_detail","hosted_on","asset_status","is_expired","asset_environment","asset_nu",
                  "asset_purchase_day","asset_expire_day","asset_applicant","asset_runner","asset_memo","asset_management_ip"]

    def get_asset_product(self, obj):
        product = obj.asset_product
        return product.product_name if product else ''

    def get_hosted_on(self, obj):
        if obj.asset_type == 'server':
            if obj.serverassets.hosted_on:
                hosted_on = obj.serverassets.hosted_on.assets.asset_management_ip
                if hosted_on != obj.asset_management_ip:
                    return hosted_on.IP
        else:
            return ''

    def get_type_detail(self, obj):
        return [obj.get_asset_type_display()+'-'+x[1] for x in obj.serverassets.server_types if x[0] == obj.serverassets.server_type][0]

    def get_is_expired(self, obj):
        from api.filter import is_expired_types
        if datetime.date.today().__gt__(obj.asset_expire_day):
            return is_expired_types[1][1]
        else:
            return is_expired_types[0][1]


class DBAssetsConfigExportSerializer(serializers.ModelSerializer):
    db_IP = serializers.SerializerMethodField()
    asset_environment = serializers.ChoiceField(choices=Assets.asset_environment_, source="get_asset_environment_display")
    asset_product = serializers.SerializerMethodField()

    class Meta:
        model = Assets
        fields = ['id', 'asset_nu', 'db_IP', 'asset_environment', 'asset_product']

    def get_db_IP(self, obj):
        return obj.asset_management_ip.IP

    def get_asset_product(self, obj):
        return obj.asset_product.product_name if obj.asset_product else ''


class DBConfigExportSerializer(serializers.ModelSerializer):
    type = serializers.ChoiceField(choices=DBConfig.db_type_, source="get_db_type_display")
    db_password = serializers.SerializerMethodField()
    db_server = DBAssetsConfigExportSerializer()

    class Meta:
        model = DBConfig
        fields = ['id', 'db_user', 'db_password', 'db_port', 'db_memo' , 'db_code', 'db_name', 'type', 'db_oracle_type', 'db_server']

    def get_db_password(self, obj):
        return CryptPwd().decrypt_pwd(obj.db_password)


class ProjectProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProjectProduct
        fields = '__all__'


class ServiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Service
        fields = '__all__'


class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = '__all__'


class ProjectConfigSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProjectConfig
        fields = '__all__'